Generic_tech
Contents
Generic_tech#
gdsfactory includes a generic Technology module in gdsfactory.generic_tech that you can use as an inspiration to create your own.
LayerMap#
A layer map maps layer names to a integer numbers pair (GDSlayer, GDSpurpose)
Each foundry uses different GDS layer numbers for different process steps.
We follow the generic layer numbers from the book “Silicon Photonics Design: From Devices to Systems Lukas Chrostowski, Michael Hochberg”.
GDS (layer, purpose) |
layer_name |
Description |
|---|---|---|
1 , 0 |
WG |
220 nm Silicon core |
2 , 0 |
SLAB150 |
150nm Silicon slab (70nm shallow Etch for grating couplers) |
3 , 0 |
SLAB90 |
90nm Silicon slab (for modulators) |
4, 0 |
DEEPTRENCH |
Deep trench |
47, 0 |
MH |
heater |
41, 0 |
M1 |
metal 1 |
45, 0 |
M2 |
metal 2 |
40, 0 |
VIAC |
VIAC to contact Ge, NPP or PPP |
44, 0 |
VIA1 |
VIA1 |
46, 0 |
PADOPEN |
Bond pad opening |
51, 0 |
UNDERCUT |
Undercut |
66, 0 |
TEXT |
Text markup |
64, 0 |
FLOORPLAN |
Mask floorplan |
[1]:
from pydantic import BaseModel
from typing import Tuple
import gdsfactory as gf
from gdsfactory.generic_tech import LAYER, LAYER_STACK
from gdsfactory.generic_tech.get_klayout_pyxs import get_klayout_pyxs
from gdsfactory.technology import LayerLevel, LayerStack
2023-02-20 17:45:58.015 | INFO | gdsfactory.config:<module>:50 - Load '/home/runner/work/gdsfactory/gdsfactory/gdsfactory' 6.43.1
[2]:
Layer = Tuple[int, int]
gf.config.rich_output()
PDK = gf.get_generic_pdk()
PDK.activate()
class GenericLayerMap(BaseModel):
"""Generic layermap based on book.
Lukas Chrostowski, Michael Hochberg, "Silicon Photonics Design",
Cambridge University Press 2015, page 353
You will need to create a new LayerMap with your specific foundry layers.
"""
WAFER: Layer = (99999, 0)
WG: Layer = (1, 0)
WGCLAD: Layer = (111, 0)
SLAB150: Layer = (2, 0)
SLAB90: Layer = (3, 0)
DEEPTRENCH: Layer = (4, 0)
GE: Layer = (5, 0)
UNDERCUT: Layer = (6, 0)
WGN: Layer = (34, 0)
WGN_CLAD: Layer = (36, 0)
N: Layer = (20, 0)
NP: Layer = (22, 0)
NPP: Layer = (24, 0)
P: Layer = (21, 0)
PP: Layer = (23, 0)
PPP: Layer = (25, 0)
GEN: Layer = (26, 0)
GEP: Layer = (27, 0)
HEATER: Layer = (47, 0)
M1: Layer = (41, 0)
M2: Layer = (45, 0)
M3: Layer = (49, 0)
VIAC: Layer = (40, 0)
VIA1: Layer = (44, 0)
VIA2: Layer = (43, 0)
PADOPEN: Layer = (46, 0)
DICING: Layer = (100, 0)
NO_TILE_SI: Layer = (71, 0)
PADDING: Layer = (67, 0)
DEVREC: Layer = (68, 0)
FLOORPLAN: Layer = (64, 0)
TEXT: Layer = (66, 0)
PORT: Layer = (1, 10)
PORTE: Layer = (1, 11)
PORTH: Layer = (70, 0)
SHOW_PORTS: Layer = (1, 12)
LABEL: Layer = (201, 0)
LABEL_SETTINGS: Layer = (202, 0)
TE: Layer = (203, 0)
TM: Layer = (204, 0)
DRC_MARKER: Layer = (205, 0)
LABEL_INSTANCE: Layer = (206, 0)
ERROR_MARKER: Layer = (207, 0)
ERROR_PATH: Layer = (208, 0)
SOURCE: Layer = (110, 0)
MONITOR: Layer = (101, 0)
class Config:
"""pydantic config."""
frozen = True
extra = "forbid"
LAYER = GenericLayerMap()
LAYER
2023-02-20 17:45:58.928 | INFO | gdsfactory.technology.layer_views:__init__:785 - Importing LayerViews from YAML file: /home/runner/work/gdsfactory/gdsfactory/gdsfactory/generic_tech/layer_views.yaml.
2023-02-20 17:45:58.935 | INFO | gdsfactory.pdk:activate:206 - 'generic' PDK is now active
GenericLayerMap( WAFER=(99999, 0), WG=(1, 0), WGCLAD=(111, 0), SLAB150=(2, 0), SLAB90=(3, 0), DEEPTRENCH=(4, 0), GE=(5, 0), UNDERCUT=(6, 0), WGN=(34, 0), WGN_CLAD=(36, 0), N=(20, 0), NP=(22, 0), NPP=(24, 0), P=(21, 0), PP=(23, 0), PPP=(25, 0), GEN=(26, 0), GEP=(27, 0), HEATER=(47, 0), M1=(41, 0), M2=(45, 0), M3=(49, 0), VIAC=(40, 0), VIA1=(44, 0), VIA2=(43, 0), PADOPEN=(46, 0), DICING=(100, 0), NO_TILE_SI=(71, 0), PADDING=(67, 0), DEVREC=(68, 0), FLOORPLAN=(64, 0), TEXT=(66, 0), PORT=(1, 10), PORTE=(1, 11), PORTH=(70, 0), SHOW_PORTS=(1, 12), LABEL=(201, 0), LABEL_SETTINGS=(202, 0), TE=(203, 0), TM=(204, 0), DRC_MARKER=(205, 0), LABEL_INSTANCE=(206, 0), ERROR_MARKER=(207, 0), ERROR_PATH=(208, 0), SOURCE=(110, 0), MONITOR=(101, 0) )
[3]:
layer_wg = gf.LAYER.WG
print(layer_wg)
(1, 0)
Extract layers#
You can also extract layers using the extract function. This function returns a new flattened Component that contains the extracted layers. A flat Component does not have references, and all the polygons are absorbed into the top cell.
[4]:
from gdsfactory.generic_tech import get_generic_pdk
PDK = get_generic_pdk()
PDK.activate()
LAYER_VIEWS = PDK.layer_views
c = LAYER_VIEWS.preview_layerset()
c
2023-02-20 17:45:59.078 | INFO | gdsfactory.technology.layer_views:__init__:785 - Importing LayerViews from YAML file: /home/runner/work/gdsfactory/gdsfactory/gdsfactory/generic_tech/layer_views.yaml.
2023-02-20 17:45:59.085 | INFO | gdsfactory.pdk:activate:206 - 'generic' PDK is now active
layerset_eeb63ddc: uid eeb63ddc, ports [], references ['rectangle_1', 'text_1', 'rectangle_2', 'text_2', 'rectangle_3', 'text_3', 'rectangle_4', 'text_4', 'rectangle_5', 'text_5', 'rectangle_6', 'text_6', 'rectangle_7', 'text_7', 'rectangle_8', 'text_8', 'rectangle_9', 'text_9', 'rectangle_10', 'text_10', 'rectangle_11', 'text_11', 'rectangle_12', 'text_12', 'rectangle_13', 'text_13', 'rectangle_14', 'text_14', 'rectangle_15', 'text_15', 'rectangle_16', 'text_16', 'rectangle_17', 'text_17', 'rectangle_18', 'text_18', 'rectangle_19', 'text_19', 'rectangle_20', 'text_20', 'rectangle_21', 'text_21', 'rectangle_22', 'text_22', 'rectangle_23', 'text_23', 'rectangle_24', 'text_24', 'rectangle_25', 'text_25', 'rectangle_26', 'text_26', 'rectangle_27', 'text_27', 'rectangle_28', 'text_28', 'rectangle_29', 'text_29', 'rectangle_30', 'text_30', 'rectangle_31', 'text_31', 'rectangle_32', 'text_32', 'rectangle_33', 'text_33', 'rectangle_34', 'text_34', 'rectangle_35', 'text_35', 'rectangle_36', 'text_36', 'rectangle_37', 'text_37', 'rectangle_38', 'text_38', 'rectangle_39', 'text_39', 'rectangle_40', 'text_40', 'rectangle_41', 'text_41', 'rectangle_42', 'text_42', 'rectangle_43', 'text_43', 'rectangle_44', 'text_44', 'rectangle_45', 'text_45', 'rectangle_46', 'text_46', 'rectangle_47', 'text_47', 'rectangle_48', 'text_48', 'rectangle_49', 'text_49', 'rectangle_50', 'text_50', 'rectangle_51', 'text_51', 'rectangle_52', 'text_52', 'rectangle_53', 'text_53', 'rectangle_54', 'text_54', 'rectangle_55', 'text_55', 'rectangle_56', 'text_56', 'rectangle_57', 'text_57', 'rectangle_58', 'text_58', 'rectangle_59', 'text_59', 'rectangle_60', 'text_60', 'rectangle_61', 'text_61', 'rectangle_62', 'text_62', 'rectangle_63', 'text_63', 'rectangle_64', 'text_64', 'rectangle_65', 'text_65', 'rectangle_66', 'text_66', 'rectangle_67', 'text_67', 'rectangle_68', 'text_68', 'rectangle_69', 'text_69', 'rectangle_70', 'text_70', 'rectangle_71', 'text_71', 'rectangle_72', 'text_72', 'rectangle_73', 'text_73', 'rectangle_74', 'text_74', 'rectangle_75', 'text_75', 'rectangle_76', 'text_76', 'rectangle_77', 'text_77', 'rectangle_78', 'text_78', 'rectangle_79', 'text_79', 'rectangle_80', 'text_80', 'rectangle_81', 'text_81', 'rectangle_82', 'text_82'], 0 polygons
[5]:
extract = c.extract(layers=(gf.LAYER.M1, gf.LAYER.VIAC))
extract
/home/runner/work/gdsfactory/gdsfactory/gdsfactory/component.py:1684: UserWarning: Component 'Unnamed_500dd4c5' contains 1 Unnamed cells
warnings.warn(
Unnamed_500dd4c5: uid 500dd4c5, ports [], references [], 19 polygons
Remove layers#
You can remove layers using the remove_layers() function.
[6]:
removed = extract.remove_layers(layers=(gf.LAYER.VIAC,))
removed
Unnamed_500dd4c5: uid 500dd4c5, ports [], references [], 8 polygons
Remap layers#
You can remap (change the polygons from one layer to another layer) using the remap_layer, which will return a new Component
[7]:
c = gf.components.straight(layer=(2, 0))
c
straight_layer2__0: uid 6e350b84, ports ['o1', 'o2'], references [], 1 polygons
[8]:
remap = c.remap_layers(layermap={(2, 0): gf.LAYER.WGN})
remap
/home/runner/work/gdsfactory/gdsfactory/gdsfactory/component.py:1684: UserWarning: Component 'Unnamed_51adbcde' contains 1 Unnamed cells
warnings.warn(
Unnamed_51adbcde: uid 51adbcde, ports ['o1', 'o2'], references [], 1 polygons
LayerViews#
Klayout shows each GDS layer with a color, style and transparency
You can define your layerViews in a klayout Layer Properties file layers.lyp or in YAML format
We recommend using YAML and then generate the lyp in klayout, as YAML is easier to modify than XML.
[9]:
from IPython.display import Code
from gdsfactory.config import PATH
Code(filename=PATH.klayout_yaml)
[9]:
LayerViews:
Waveguide:
layer: [1, 0]
hatch_pattern: dotted
width: 1
color: "#ff9d9d"
WGCLAD:
layer: [111, 0]
layer_in_name: true
hatch_pattern: coarsely dotted
visible: false
width: 1
color: "silver"
SLAB150:
layer: [2, 0]
layer_in_name: true
hatch_pattern: coarsely dotted
transparent: true
width: 1
color: "cyan"
SLAB90:
layer: [3, 0]
layer_in_name: true
hatch_pattern: hollow
transparent: true
width: 1
color: "#805000"
SHALLOWETCH:
layer: [2, 6]
layer_in_name: true
hatch_pattern: coarsely dotted
color: "blue"
DEEPETCH:
layer: [3, 6]
layer_in_name: true
hatch_pattern: coarsely dotted
color: "#cc0000"
SLAB150CLAD:
layer: [2, 9]
layer_in_name: true
frame_color: "#9999cc"
fill_color: "#80a8ff"
hatch_pattern: coarsely dotted
visible: false
width: 1
SLAB90CLAD:
layer: [3, 1]
layer_in_name: true
frame_color: "#9999cc"
fill_color: "#80a8ff"
hatch_pattern: hollow
visible: false
width: 1
Doping:
group_members:
N:
layer: [20, 0]
layer_in_name: true
hatch_pattern: lightly left-hatched
width: 1
color: "red"
NP:
layer: [22, 0]
layer_in_name: true
hatch_pattern: lightly left-hatched
width: 1
color: "red"
NPP:
layer: [24, 0]
layer_in_name: true
hatch_pattern: coarsely dotted
width: 1
color: "red"
P_210:
layer: [21, 0]
hatch_pattern: lightly left-hatched
transparent: true
width: 1
color: "blue"
PP:
layer: [23, 0]
layer_in_name: true
hatch_pattern: lightly left-hatched
width: 1
color: "blue"
PPP:
layer: [25, 0]
layer_in_name: true
hatch_pattern: strongly left-hatched dense
width: 1
color: "blue"
PDPP:
layer: [27, 0]
layer_in_name: true
hatch_pattern: lightly cross-hatched
width: 1
color: "#ccb27f"
GENPP:
layer: [26, 0]
layer_in_name: true
hatch_pattern: plus
width: 1
color: "#cc00cc"
GEPPP:
layer: [29, 0]
layer_in_name: true
hatch_pattern: plus
width: 1
color: "#cc00cc"
WGN_Nitride:
layer: [34, 0]
layer_in_name: true
hatch_pattern: left-hatched
transparent: true
width: 1
color: "#ff8000"
WGNCLAD:
layer: [36, 0]
layer_in_name: true
hatch_pattern: coarsely dotted
visible: false
width: 1
color: "silver"
GE:
layer: [5, 0]
layer_in_name: true
hatch_pattern: dotted
width: 1
color: "magenta"
SILICIDE:
layer: [39, 0]
layer_in_name: true
hatch_pattern: strongly right-hatched sparse
width: 1
color: "#cc4c00"
MH:
layer: [47, 0]
layer_in_name: true
hatch_pattern: hollow
transparent: true
width: 1
color: "#ff8000"
M1:
layer: [41, 0]
layer_in_name: true
hatch_pattern: hollow
width: 1
color: "#01ff6b"
brightness: -16
M2:
layer: [45, 0]
layer_in_name: true
hatch_pattern: hollow
width: 1
color: "#008050"
M3:
layer: [49, 0]
layer_in_name: true
frame_color: "teal"
fill_color: "#800057"
hatch_pattern: hollow
VIAC:
layer: [40, 0]
layer_in_name: true
hatch_pattern: hollow
width: 1
color: "#cc4c00"
VIA1:
layer: [44, 0]
layer_in_name: true
hatch_pattern: hollow
width: 1
color: "grey"
VIA2:
layer: [43, 0]
layer_in_name: true
hatch_pattern: hollow
width: 1
color: "#805000"
CAPACITOR:
layer: [42, 0]
layer_in_name: true
hatch_pattern: dotted
width: 1
color: "#805000"
METALOPEN:
layer: [46, 0]
layer_in_name: true
hatch_pattern: cross-hatched
width: 1
color: "#606060"
DEEPTRENCH:
layer: [4, 0]
layer_in_name: true
hatch_pattern: lightly right-hatched
width: 1
color: "#9999cc"
OXIDE_ETCH:
layer: [6, 0]
layer_in_name: true
hatch_pattern: strongly left-hatched dense
width: 1
color: "black"
SITILES:
layer: [190, 0]
layer_in_name: true
hatch_pattern: coarsely dotted
width: 1
color: "black"
M1TILES:
layer: [191, 0]
layer_in_name: true
hatch_pattern: coarsely dotted
width: 1
color: "#91ff00"
LABEL_OPTICAL_IO:
layer: [201, 0]
layer_in_name: true
hatch_pattern: hollow
width: 1
color: "blue"
LABEL_SETTINGS:
layer: [202, 0]
layer_in_name: true
hatch_pattern: hollow
visible: false
width: 1
color: "magenta"
TE:
layer: [203, 0]
layer_in_name: true
transparent: true
width: 1
color: "blue"
TM:
layer: [204, 0]
layer_in_name: true
width: 1
color: "red"
LABEL_INSTANCES:
layer: [206, 0]
layer_in_name: true
hatch_pattern: lightly left-hatched
color: "blue"
DICING:
layer: [65, 0]
layer_in_name: true
hatch_pattern: coarsely dotted
width: 1
color: "#cc0000"
DRC_EXCLUDE:
layer: [67, 0]
layer_in_name: true
hatch_pattern: hollow
visible: false
width: 2
color: "black"
FLOORPLAN:
layer: [64, 0]
layer_in_name: true
hatch_pattern: hollow
color: "black"
simulation:
group_members:
SIM_REGION:
layer: [100, 0]
layer_in_name: true
hatch_pattern: hollow
color: "black"
MONITOR:
layer: [101, 0]
layer_in_name: true
hatch_pattern: hollow
color: "blue"
SOURCE:
layer: [110, 0]
layer_in_name: true
hatch_pattern: hollow
color: "red"
Lumerical:
layer: [733, 0]
hatch_pattern: hollow
width: 3
color: "#800057"
DevRec:
layer: [68, 0]
hatch_pattern: hollow
visible: false
transparent: true
width: 1
color: "#004080"
PinRec:
layer: [1, 10]
hatch_pattern: hollow
color: "#404040"
FbrTgt:
layer: [81, 0]
hatch_pattern: lightly right-hatched
width: 2
color: "#004080"
Text:
layer: [66, 0]
hatch_pattern: hollow
width: 1
color: "blue"
Errors:
layer: [69, 0]
hatch_pattern: hollow
width: 1
color: "blue"
PinRecM:
layer: [1, 11]
hatch_pattern: hollow
width: 1
color: "#004080"
XSECTION:
group_members:
XS_BOX:
layer: [300, 0]
layer_in_name: true
width: 1
color: "#f3ff80"
XS_SI:
layer: [301, 0]
layer_in_name: true
width: 1
color: "black"
XS_SIN:
layer: [319, 0]
layer_in_name: true
width: 1
color: "black"
XS_N:
layer: [320, 0]
layer_in_name: true
width: 1
color: "#008ca5"
XS_NPP:
layer: [321, 0]
layer_in_name: true
width: 1
color: "#004ca5"
XS_P:
layer: [330, 0]
layer_in_name: true
width: 1
color: "#00f233"
XS_PDPP:
layer: [327, 0]
layer_in_name: true
width: 1
color: "#00f233"
XS_PPP:
layer: [331, 0]
layer_in_name: true
width: 1
color: "#00b233"
XS_SI_SLAB:
layer: [313, 0]
layer_in_name: true
width: 1
color: "#80a8ff"
XS_OVERLAY:
layer: [311, 0]
layer_in_name: true
width: 1
color: "blue"
XS_OX_SI:
layer: [302, 0]
layer_in_name: true
width: 1
color: "#f3ff80"
XS_GE:
layer: [315, 0]
layer_in_name: true
width: 1
color: "#004ca5"
XS_VIAC:
layer: [303, 0]
layer_in_name: true
width: 1
color: "grey"
XS_M1:
layer: [304, 0]
layer_in_name: true
width: 1
color: "green"
XS_OXIDE_M1:
layer: [305, 0]
layer_in_name: true
width: 1
color: "#f3ff80"
XS_MH:
layer: [306, 0]
layer_in_name: true
width: 1
color: "green"
XS_OXIDE_M2:
layer: [307, 0]
layer_in_name: true
width: 1
color: "#f3ff80"
XS_OXIDE_MH:
layer: [317, 0]
layer_in_name: true
width: 1
color: "#f3ff80"
XS_OXIDE_ML:
layer: [309, 0]
layer_in_name: true
width: 1
color: "#f3ff80"
XS_VIA1:
layer: [308, 0]
layer_in_name: true
width: 1
color: "grey"
XS_M2:
layer: [399, 0]
layer_in_name: true
width: 1
color: "#805000"
XS_OXIDE_M3:
layer: [311, 0]
layer_in_name: true
width: 1
color: "#f3ff80"
XS_VIA2:
layer: [310, 0]
layer_in_name: true
width: 1
color: "grey"
XS_SIN2:
layer: [305, 0]
layer_in_name: true
width: 1
color: "#805000"
DRC_MARKER:
layer: [205, 0]
layer_in_name: true
transparent: true
width: 3
color: "red"
ERROR_MARKER:
layer: [207, 0]
layer_in_name: true
transparent: true
width: 3
color: "red"
NOTILE_M1:
layer: [71, 0]
layer_in_name: true
hatch_pattern: coarsely dotted
visible: false
color: "grey"
NOTILE_M2:
layer: [72, 0]
layer_in_name: true
hatch_pattern: coarsely dotted
visible: false
color: "grey"
NOTILE_M3:
layer: [73, 0]
layer_in_name: true
hatch_pattern: coarsely dotted
visible: false
color: "#606060"
SHOW_PORTS:
layer: [1, 12]
layer_in_name: true
hatch_pattern: lightly left-hatched
color: "#ff80a8"
Once you modify the YAML file you can easily write it to klayout.
[10]:
help(gf.generic_tech.write_lyp)
Help on function write_lyp in module gdsfactory.generic_tech:
write_lyp() -> 'None'
Write from YAML to Klayout lyp file
[11]:
c = LAYER_VIEWS.preview_layerset()
c
layerset_f12a4bf9: uid f12a4bf9, ports [], references ['rectangle_1', 'text_1', 'rectangle_2', 'text_2', 'rectangle_3', 'text_3', 'rectangle_4', 'text_4', 'rectangle_5', 'text_5', 'rectangle_6', 'text_6', 'rectangle_7', 'text_7', 'rectangle_8', 'text_8', 'rectangle_9', 'text_9', 'rectangle_10', 'text_10', 'rectangle_11', 'text_11', 'rectangle_12', 'text_12', 'rectangle_13', 'text_13', 'rectangle_14', 'text_14', 'rectangle_15', 'text_15', 'rectangle_16', 'text_16', 'rectangle_17', 'text_17', 'rectangle_18', 'text_18', 'rectangle_19', 'text_19', 'rectangle_20', 'text_20', 'rectangle_21', 'text_21', 'rectangle_22', 'text_22', 'rectangle_23', 'text_23', 'rectangle_24', 'text_24', 'rectangle_25', 'text_25', 'rectangle_26', 'text_26', 'rectangle_27', 'text_27', 'rectangle_28', 'text_28', 'rectangle_29', 'text_29', 'rectangle_30', 'text_30', 'rectangle_31', 'text_31', 'rectangle_32', 'text_32', 'rectangle_33', 'text_33', 'rectangle_34', 'text_34', 'rectangle_35', 'text_35', 'rectangle_36', 'text_36', 'rectangle_37', 'text_37', 'rectangle_38', 'text_38', 'rectangle_39', 'text_39', 'rectangle_40', 'text_40', 'rectangle_41', 'text_41', 'rectangle_42', 'text_42', 'rectangle_43', 'text_43', 'rectangle_44', 'text_44', 'rectangle_45', 'text_45', 'rectangle_46', 'text_46', 'rectangle_47', 'text_47', 'rectangle_48', 'text_48', 'rectangle_49', 'text_49', 'rectangle_50', 'text_50', 'rectangle_51', 'text_51', 'rectangle_52', 'text_52', 'rectangle_53', 'text_53', 'rectangle_54', 'text_54', 'rectangle_55', 'text_55', 'rectangle_56', 'text_56', 'rectangle_57', 'text_57', 'rectangle_58', 'text_58', 'rectangle_59', 'text_59', 'rectangle_60', 'text_60', 'rectangle_61', 'text_61', 'rectangle_62', 'text_62', 'rectangle_63', 'text_63', 'rectangle_64', 'text_64', 'rectangle_65', 'text_65', 'rectangle_66', 'text_66', 'rectangle_67', 'text_67', 'rectangle_68', 'text_68', 'rectangle_69', 'text_69', 'rectangle_70', 'text_70', 'rectangle_71', 'text_71', 'rectangle_72', 'text_72', 'rectangle_73', 'text_73', 'rectangle_74', 'text_74', 'rectangle_75', 'text_75', 'rectangle_76', 'text_76', 'rectangle_77', 'text_77', 'rectangle_78', 'text_78', 'rectangle_79', 'text_79', 'rectangle_80', 'text_80', 'rectangle_81', 'text_81', 'rectangle_82', 'text_82'], 0 polygons
By default the generic PDK has some layers that are not visible and therefore are not shown.
[12]:
c_wg_clad = c.extract(layers=gf.LAYER.WGCLAD)
c_wg_clad
/home/runner/work/gdsfactory/gdsfactory/gdsfactory/component.py:1684: UserWarning: Component 'Unnamed_36e7280b' contains 1 Unnamed cells
warnings.warn(
Unnamed_36e7280b: uid 36e7280b, ports [], references [], 13 polygons
[13]:
LAYER_VIEWS.layer_views["WGCLAD"]
LayerView( name='WGCLAD', info=None, layer=(111, 0), layer_in_name=True, frame_color=Color('silver', rgb=(192, 192, 192)), fill_color=Color('silver', rgb=(192, 192, 192)), frame_brightness=0, fill_brightness=0, hatch_pattern='coarsely dotted', line_style=None, valid=True, visible=False, transparent=False, width=1, marked=False, xfill=False, animation=0, group_members={} )
[14]:
LAYER_VIEWS.layer_views["WGCLAD"].visible
False
You can make it visible
[15]:
LAYER_VIEWS.layer_views["WGCLAD"].visible = True
[16]:
LAYER_VIEWS.layer_views["WGCLAD"].visible
True
[17]:
c_wg_clad = c.extract(layers=gf.LAYER.WGCLAD)
c_wg_clad
/home/runner/work/gdsfactory/gdsfactory/gdsfactory/component.py:1684: UserWarning: Component 'Unnamed_df1cbc3e' contains 1 Unnamed cells
warnings.warn(
Unnamed_df1cbc3e: uid df1cbc3e, ports [], references [], 13 polygons
LayerStack#
Each layer also includes the information of thickness and position of each layer.
This LayerStack can be used for creating a 3D model with Component.to_3d or running Simulations.
A GDS has different layers to describe the different fabrication process steps. And each grown layer needs thickness information and z-position in the stack.

Lets define the layer stack for the generic layers in the generic_technology.
[18]:
nm = 1e-3
def get_layer_stack(
thickness_wg: float = 220 * nm,
thickness_slab_deep_etch: float = 90 * nm,
thickness_clad: float = 3.0,
thickness_nitride: float = 350 * nm,
thickness_ge: float = 500 * nm,
gap_silicon_to_nitride: float = 100 * nm,
zmin_heater: float = 1.1,
zmin_metal1: float = 1.1,
thickness_metal1: float = 700 * nm,
zmin_metal2: float = 2.3,
thickness_metal2: float = 700 * nm,
zmin_metal3: float = 3.2,
thickness_metal3: float = 2000 * nm,
substrate_thickness: float = 10.0,
box_thickness: float = 3.0,
undercut_thickness: float = 5.0,
) -> LayerStack:
"""Returns generic LayerStack.
based on paper https://www.degruyter.com/document/doi/10.1515/nanoph-2013-0034/html
Args:
thickness_wg: waveguide thickness in um.
thickness_slab_deep_etch: for deep etched slab.
thickness_clad: cladding thickness in um.
thickness_nitride: nitride thickness in um.
thickness_ge: germanium thickness.
gap_silicon_to_nitride: distance from silicon to nitride in um.
zmin_heater: TiN heater.
zmin_metal1: metal1.
thickness_metal1: metal1 thickness.
zmin_metal2: metal2.
thickness_metal2: metal2 thickness.
zmin_metal3: metal3.
thickness_metal3: metal3 thickness.
substrate_thickness: substrate thickness in um.
box_thickness: bottom oxide thickness in um.
undercut_thickness: thickness of the silicon undercut.
"""
class GenericLayerStack(LayerStack):
substrate = LayerLevel(
layer=LAYER.WAFER,
thickness=substrate_thickness,
zmin=-substrate_thickness - box_thickness,
material="si",
info={"mesh_order": 99},
)
box = LayerLevel(
layer=LAYER.WAFER,
thickness=box_thickness,
zmin=-box_thickness,
material="sio2",
info={"mesh_order": 99},
)
core = LayerLevel(
layer=LAYER.WG,
thickness=thickness_wg,
zmin=0.0,
material="si",
info={"mesh_order": 1},
sidewall_angle=10,
width_to_z=0.5,
)
clad = LayerLevel(
# layer=LAYER.WGCLAD,
layer=LAYER.WAFER,
zmin=0.0,
material="sio2",
thickness=thickness_clad,
info={"mesh_order": 10},
)
slab150 = LayerLevel(
layer=LAYER.SLAB150,
thickness=150e-3,
zmin=0,
material="si",
info={"mesh_order": 3},
)
slab90 = LayerLevel(
layer=LAYER.SLAB90,
thickness=thickness_slab_deep_etch,
zmin=0.0,
material="si",
info={"mesh_order": 2},
)
nitride = LayerLevel(
layer=LAYER.WGN,
thickness=thickness_nitride,
zmin=thickness_wg + gap_silicon_to_nitride,
material="sin",
info={"mesh_order": 2},
)
ge = LayerLevel(
layer=LAYER.GE,
thickness=thickness_ge,
zmin=thickness_wg,
material="ge",
info={"mesh_order": 1},
)
undercut = LayerLevel(
layer=LAYER.UNDERCUT,
thickness=-undercut_thickness,
zmin=-box_thickness,
material="air",
z_to_bias=[
[0, 0.3, 0.6, 0.8, 0.9, 1],
[-0, -0.5, -1, -1.5, -2, -2.5],
],
info={"mesh_order": 1},
)
via_contact = LayerLevel(
layer=LAYER.VIAC,
thickness=zmin_metal1 - thickness_slab_deep_etch,
zmin=thickness_slab_deep_etch,
material="Aluminum",
info={"mesh_order": 1},
sidewall_angle=-10,
width_to_z=0,
)
metal1 = LayerLevel(
layer=LAYER.M1,
thickness=thickness_metal1,
zmin=zmin_metal1,
material="Aluminum",
info={"mesh_order": 2},
)
heater = LayerLevel(
layer=LAYER.HEATER,
thickness=750e-3,
zmin=zmin_heater,
material="TiN",
info={"mesh_order": 1},
)
via1 = LayerLevel(
layer=LAYER.VIA1,
thickness=zmin_metal2 - (zmin_metal1 + thickness_metal1),
zmin=zmin_metal1 + thickness_metal1,
material="Aluminum",
info={"mesh_order": 2},
)
metal2 = LayerLevel(
layer=LAYER.M2,
thickness=thickness_metal2,
zmin=zmin_metal2,
material="Aluminum",
info={"mesh_order": 2},
)
via2 = LayerLevel(
layer=LAYER.VIA2,
thickness=zmin_metal3 - (zmin_metal2 + thickness_metal2),
zmin=zmin_metal2 + thickness_metal2,
material="Aluminum",
info={"mesh_order": 1},
)
metal3 = LayerLevel(
layer=LAYER.M3,
thickness=thickness_metal3,
zmin=zmin_metal3,
material="Aluminum",
info={"mesh_order": 2},
)
return GenericLayerStack()
layer_stack220 = get_layer_stack(thickness_wg=0.220)
[19]:
import gdsfactory as gf
c = gf.components.straight_heater_doped_rib(length=100)
c
straight_heater_doped_r_be2f5e0f: uid 45ab7276, ports ['o1', 'o2', 'top_e1', 'top_e2', 'top_e3', 'top_e4', 'bot_e1', 'bot_e2', 'bot_e3', 'bot_e4'], references ['straight_1', 'taper_cross_section_1', 'taper_cross_section_2', 'via_stack_1', 'via_stack_2', 'via_stack_3', 'via_stack_4', 'via_stack_5', 'via_stack_6', 'via_stack_7', 'via_stack_8', 'via_stack_9', 'via_stack_10', 'via_stack_11', 'via_stack_12', 'via_stack_13', 'via_stack_14', 'via_stack_15', 'via_stack_16', 'via_stack_17', 'via_stack_18'], 0 polygons
[20]:
import gdsfactory as gf
c = gf.components.straight_heater_metal(length=40)
c
straight_heater_metal_u_d99b3f2a: uid db924e1d, ports ['o1', 'o2', 'e1', 'e2'], references ['component_sequence_1', 'via_stack_1', 'via_stack_2', 'taper_1', 'taper_2'], 0 polygons
[21]:
scene = c.to_3d(layer_stack=layer_stack220)
scene.show()
[21]:
[22]:
# lets assume we have 0.900 silicon instead of 0.220um, You will see a much thicker waveguide under the metal heater.
layer_stack9000 = get_layer_stack(thickness_wg=0.9)
scene = c.to_3d(layer_stack=layer_stack9000)
scene.show()
[22]:
3D rendering#
To render components in 3D you will need to define two things:
LayerStack: for each layer contains thickness of each material and z position
LayerViews: for each layer contains view (color, pattern, opacity). You can load it with
gf.technology.LayerView.load_lyp()
[23]:
heater = gf.components.straight_heater_metal(length=50)
heater
straight_heater_metal_u_d92d12b4: uid 34618ea9, ports ['o1', 'o2', 'e1', 'e2'], references ['component_sequence_1', 'via_stack_1', 'via_stack_2', 'taper_1', 'taper_2'], 0 polygons
[24]:
scene = heater.to_3d()
scene.show()
[24]:
Klayout 2.5D view#
From the LayerStack you can generate the KLayout 2.5D view script.
[25]:
LAYER_STACK.get_klayout_3d_script()
z(input(99999, 0), zstart: -13.0, zstop: -3.0, name: 'substrate: si 99999/0')
z(input(99999, 0), zstart: -3.0, zstop: 0.0, name: 'box: sio2 99999/0')
z(input(1, 0), zstart: 0.0, zstop: 0.22, name: 'core: si 1/0')
z(input(99999, 0), zstart: 0.0, zstop: 3.0, name: 'clad: sio2 99999/0')
z(input(2, 0), zstart: 0.0, zstop: 0.15, name: 'slab150: si 2/0')
z(input(3, 0), zstart: 0.0, zstop: 0.09, name: 'slab90: si 3/0')
z(input(34, 0), zstart: 0.32, zstop: 0.67, name: 'nitride: sin 34/0')
z(input(5, 0), zstart: 0.22, zstop: 0.72, name: 'ge: ge 5/0')
z(input(6, 0), zstart: -3.0, zstop: -8.0, name: 'undercut: air 6/0')
z(input(40, 0), zstart: 0.09, zstop: 1.1, name: 'via_contact: Aluminum 40/0')
z(input(41, 0), zstart: 1.1, zstop: 1.8, name: 'metal1: Aluminum 41/0')
z(input(47, 0), zstart: 1.1, zstop: 1.85, name: 'heater: TiN 47/0')
z(input(44, 0), zstart: 1.8, zstop: 2.3, name: 'via1: Aluminum 44/0')
z(input(45, 0), zstart: 2.3, zstop: 3.0, name: 'metal2: Aluminum 45/0')
z(input(43, 0), zstart: 3.0, zstop: 3.2, name: 'via2: Aluminum 43/0')
z(input(49, 0), zstart: 3.2, zstop: 5.2, name: 'metal3: Aluminum 49/0')
"z(input(99999, 0), zstart: -13.0, zstop: -3.0, name: 'substrate: si 99999/0')\nz(input(99999, 0), zstart: -3.0, zstop: 0.0, name: 'box: sio2 99999/0')\nz(input(1, 0), zstart: 0.0, zstop: 0.22, name: 'core: si 1/0')\nz(input(99999, 0), zstart: 0.0, zstop: 3.0, name: 'clad: sio2 99999/0')\nz(input(2, 0), zstart: 0.0, zstop: 0.15, name: 'slab150: si 2/0')\nz(input(3, 0), zstart: 0.0, zstop: 0.09, name: 'slab90: si 3/0')\nz(input(34, 0), zstart: 0.32, zstop: 0.67, name: 'nitride: sin 34/0')\nz(input(5, 0), zstart: 0.22, zstop: 0.72, name: 'ge: ge 5/0')\nz(input(6, 0), zstart: -3.0, zstop: -8.0, name: 'undercut: air 6/0')\nz(input(40, 0), zstart: 0.09, zstop: 1.1, name: 'via_contact: Aluminum 40/0')\nz(input(41, 0), zstart: 1.1, zstop: 1.8, name: 'metal1: Aluminum 41/0')\nz(input(47, 0), zstart: 1.1, zstop: 1.85, name: 'heater: TiN 47/0')\nz(input(44, 0), zstart: 1.8, zstop: 2.3, name: 'via1: Aluminum 44/0')\nz(input(45, 0), zstart: 2.3, zstop: 3.0, name: 'metal2: Aluminum 45/0')\nz(input(43, 0), zstart: 3.0, zstop: 3.2, name: 'via2: Aluminum 43/0')\nz(input(49, 0), zstart: 3.2, zstop: 5.2, name: 'metal3: Aluminum 49/0')\n"
Then you go go Tools → Manage Technologies

and Paste the script

Klayout cross-section#
You can also install the KLayout cross-section plugin

This is not integrated with the LayerStack but you can use the script in gdsfactory.generic_tech.get_klayout_pyxs and customize it for your technology.
[26]:
nm = 1e-3
if __name__ == "__main__":
script = get_klayout_pyxs(
t_box=2.0,
t_slab=110 * nm,
t_si=220 * nm,
t_ge=400 * nm,
t_nitride=400 * nm,
h_etch1=0.07,
h_etch2=0.06,
h_etch3=0.09,
t_clad=0.6,
t_m1=0.5,
t_m2=0.5,
t_m3=2.0,
gap_m1_m2=0.6,
gap_m2_m3=0.3,
t_heater=0.1,
gap_oxide_nitride=0.82,
t_m1_oxide=0.6,
t_m2_oxide=2.0,
t_m3_oxide=0.5,
layer_wg=LAYER.WG,
layer_fc=LAYER.SLAB150,
layer_rib=LAYER.SLAB90,
layer_n=LAYER.N,
layer_np=LAYER.NP,
layer_npp=LAYER.NPP,
layer_p=LAYER.P,
layer_pp=LAYER.PP,
layer_ppp=LAYER.PPP,
layer_PDPP=LAYER.GEP,
layer_nitride=LAYER.WGN,
layer_Ge=LAYER.GE,
layer_GePPp=LAYER.GEP,
layer_GeNPP=LAYER.GEN,
layer_viac=LAYER.VIAC,
layer_viac_slot=LAYER.VIAC,
layer_m1=LAYER.M1,
layer_mh=LAYER.HEATER,
layer_via1=LAYER.VIA1,
layer_m2=LAYER.M2,
layer_via2=LAYER.VIA2,
layer_m3=LAYER.M3,
layer_open=LAYER.PADOPEN,
)
# script_path = pathlib.Path(__file__).parent.absolute() / "xsection_planarized.pyxs"
# script_path.write_text(script)
print(script)
t_box=2.0
t_slab=0.11
t_si=0.22
t_ge=0.4
t_nitride=0.4
h_etch1=0.07
h_etch2=0.06
h_etch3=0.09
t_clad=0.6
t_m1=0.5
t_m2=0.5
t_m3=2.0
t_heater=0.1
gap_m1_m2=0.6
gap_m2_m3=0.3
gap_oxide_nitride=0.82
t_m1_oxide=0.6
t_m2_oxide=2.0
t_m3_oxide=0.5
l_wg = layer('1/0')
l_fc = layer('2/0')
l_rib = layer('3/0')
l_n = layer('20/0')
l_np = layer('22/0')
l_npp = layer('24/0')
l_p = layer('21/0')
l_pp = layer('23/0')
l_ppp = layer('25/0')
l_PDPP = layer('27/0')
l_bottom_implant = l_PDPP
l_nitride = layer('34/0')
l_Ge = layer('5/0')
l_GePPp = layer('27/0')
l_GeNPP = layer('26/0')
l_viac = layer('40/0')
l_viac_slot = layer('40/0')
l_m1 = layer('41/0')
l_mh = layer('47/0')
l_via1 = layer('44/0')
l_m2 = layer('45/0')
l_via2 = layer('43/0')
l_m3 = layer('49/0')
l_open = layer('46/0')
l_top_implant = l_GePPp.or_(l_GeNPP)
l_viac = l_viac.or_(l_viac_slot)
# Declare the basic accuracy used to remove artifacts for example: delta(5 * dbu)
delta(dbu)
depth(12.0)
height(12.0)
################ front-end
l_wg_etch1 = l_wg.inverted() # protects ridge
l_wg_etch2 = (
l_fc.or_(l_wg)
).inverted() # protects ridge and grating couplers from the etch down to the slab (forms rib straights)
l_wg_etch3 = (
l_rib.or_(l_fc).or_(l_wg)
).inverted() # protects ridge, grating couplers and rib straights from the final etch to form strip straights
################ back-end
substrate = bulk
box = deposit(t_box)
si = deposit(t_si)
################ silicon etch to for the passives
mask(l_wg_etch1).etch(
h_etch1, 0.0, mode="round", into=[si]
) # 70nm etch for GC, rib and strip
mask(l_wg_etch2).etch(
h_etch2, 0.0, mode="round", into=[si]
) # 60nm etch after 70nm = 130nm etch (90nm slab)
mask(l_wg_etch3).etch(
h_etch3, 0.0, mode="round", into=[si]
) # etches the remaining 90nm slab for strip straights
output("300/0", box)
output("301/0", si)
############### doping
mask(l_bottom_implant).etch(t_si, 0.0, mode="round", into=[si])
bottom_implant = mask(l_bottom_implant).grow(t_si, 0.0, mode="round")
mask(l_n).etch(t_slab, 0.0, mode="round", into=[si])
n = mask(l_n).grow(t_slab, 0.0, mode="round")
mask(l_p).etch(t_slab, 0.0, mode="round", into=[si])
p = mask(l_p).grow(t_slab, 0.0, mode="round")
mask(l_np).etch(t_slab, 0.0, mode="round", into=[n, p, si, bottom_implant])
np = mask(l_np).grow(t_slab, 0.0, mode="round")
mask(l_pp).etch(t_slab, 0.0, mode="round", into=[n, p, si, bottom_implant])
pp = mask(l_pp).grow(t_slab, 0.0, mode="round")
mask(l_npp).etch(t_slab, 0.0, mode="round", into=[n, p, np, pp, si, bottom_implant])
npp = mask(l_npp).grow(t_slab, 0.0, mode="round")
mask(l_ppp).etch(t_slab, 0.0, mode="round", into=[n, p, np, pp, si, bottom_implant])
ppp = mask(l_ppp).grow(t_slab, 0.0, mode="round")
output("327/0", bottom_implant)
output("330/0", p)
output("320/0", n)
output("321/0", npp)
output("331/0", ppp)
################ Ge
Ge = mask(l_Ge).grow(t_ge, 0, bias=0.0, taper=10)
output("315/0", Ge)
################ Nitride
ox_nitride = deposit(2 * gap_oxide_nitride, 2 * gap_oxide_nitride)
planarize(less=gap_oxide_nitride, into=[ox_nitride])
output("302/0", ox_nitride)
nitride = mask(l_nitride).grow(t_nitride, 0, bias=0.0, taper=10)
output("305/0", nitride)
################# back-end
################# VIAC, M1 and MH
ox_si = deposit(t_clad + t_ge + t_nitride, t_clad + t_ge + t_nitride, mode="round")
planarize(less=t_ge + t_nitride, into=[ox_si])
mask(l_viac).etch(
t_clad + t_ge + t_nitride + gap_oxide_nitride, taper=4, into=[ox_si, ox_nitride]
)
viac = deposit(2 * t_clad, 2 * t_clad)
planarize(less=2 * t_clad, into=[viac])
mh = deposit(t_heater, t_heater)
mask(l_mh.inverted()).etch(t_heater + t_heater, into=[mh])
m1 = deposit(t_m1, t_m1)
mask(l_m1.inverted()).etch(t_m1 + t_m1, into=[m1])
output("306/0", mh)
output("399/0", m1)
output("302/0", ox_si)
output("303/0", viac)
################# VIA1 and M2
ox_m1 = deposit(2 * t_m1_oxide, 2 * t_m1_oxide, mode="round")
planarize(less=t_m1_oxide, into=[ox_m1])
mask(l_via1).etch(t_m1_oxide + gap_m1_m2, taper=4, into=[ox_m1])
via1 = deposit(t_m2, t_m2)
mask(l_m2.inverted()).etch(t_m2, taper=4, into=[via1])
output("308/0", via1)
ox_m2 = deposit(2 * t_m2_oxide, 2 * t_m2_oxide, mode="round")
planarize(less=t_m2_oxide, into=[ox_m2])
output("309/0", ox_m2)
output("307/0", ox_m1)
################# VIA2 and M3
mask(l_via2).etch(t_m2_oxide + gap_m2_m3, taper=4, into=[ox_m2, ox_m2])
via2 = deposit(t_m3, t_m3)
mask(l_m3.inverted()).etch(t_m3, taper=4, into=[via2])
output("310/0", via2)
################# passivation and ML Open
ox_m3 = deposit(t_m3_oxide, t_m3_oxide, mode="round")
mask(l_open).etch(t_m3_oxide + t_m3_oxide, into=[ox_m3], taper=5)
output("311/0", ox_m3)
